﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using System.IO;
using System.Xml.Serialization;

namespace Blokus.Scenes
{
    public class SceneHighscores : Scene
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        private SpriteFont menuFont;
        private KeyboardState keyPrevState;
        private GamePadState gpPrevState;
        public static List<string> menuItems = new List<string>();
        public static int[] highscores = new int[10];
        public static int newHighscore = -1;
        private Texture2D texBG;
        private float aspectRatio;
        private RenderTarget2D backgroundRenderTarget;
        public bool HSLoaded = false;


        // Safeguard against multiple save/load happening at the same time
        private bool Saving { get; set; }
        private bool Loading { get; set; }

        public SceneHighscores(bool addMenu)
        {
            if (!addMenu)
                return;
            menuItems.Add("HIGH SCORES");
            for (int ct = 0; ct < 10; ct++)
            {
                if (!HSLoaded)
                    highscores[ct] = 0;
                menuItems.Add(highscores[ct].ToString());
            }
        }

        public override void LoadContent(ContentManager content, GraphicsDeviceManager graphics)
        {
            this.graphics = graphics;
            //load font
            menuFont = content.Load<SpriteFont>("gamefont");
            backgroundRenderTarget = new RenderTarget2D(graphics.GraphicsDevice, 1280, 800);
            spriteBatch = new SpriteBatch(graphics.GraphicsDevice);

            texBG = content.Load<Texture2D>("Textures\\background");
            aspectRatio = graphics.GraphicsDevice.Viewport.AspectRatio;

            try
            {
                this.LoadSomething();
            }
            catch (Exception e)
            {

            }
            finally
            {
            }

        }

        public override Blokus.GameState Update(GameTime gameTime)
        {
            //number of menu items minus one
            //get keys
            GamePadState currGPState = GamePad.GetState(PlayerIndex.One);
            bool kEnter = Keyboard.GetState().IsKeyDown(Keys.Enter) && !keyPrevState.IsKeyDown(Keys.Enter)
                || Keyboard.GetState().IsKeyDown(Keys.Escape) && !keyPrevState.IsKeyDown(Keys.Escape)
                || currGPState.IsButtonDown(Buttons.A) && !gpPrevState.IsButtonDown(Buttons.A)
                || currGPState.IsButtonDown(Buttons.B) && !gpPrevState.IsButtonDown(Buttons.B);



            //check for menu item selected
            if (kEnter)
            {
                return Blokus.GameState.MENU;
            }
            //reset previous keyboard state
            keyPrevState = Keyboard.GetState();
            gpPrevState = GamePad.GetState(PlayerIndex.One);

            return Blokus.GameState.HIGHSCORES;
        }

        public override void Draw(GameTime gameTime)
        {
            //graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
            graphics.GraphicsDevice.SetRenderTarget(backgroundRenderTarget);

            spriteBatch.Begin();
            spriteBatch.Draw(texBG, new Rectangle(0, 0, 1280, 800), Color.White);
            //menu items
            for (int ct = 0; ct < menuItems.Count; ct++)
            {
                Color clr = Color.White;
                Random random = new Random();
                if (newHighscore == ct - 1 && ct > 0)
                    clr = new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble());
                int dx = 0, dy = 0;
                if (ct == 0)
                    dx += 300;
                if (ct > 5)
                {
                    dx += 650;
                    dy -= 250;
                }
                string menuStr = menuItems[ct];
                spriteBatch.DrawString(menuFont, menuStr, new Vector2(250+dx, 200+dy + ct * 50), clr);
            }
            spriteBatch.End();

            //BackgroundEffects.drawBGEffects(gameTime, aspectRatio, backgroundRenderTarget);
        
        }
        public override void ResetPrevKeys()
        {
            keyPrevState = Keyboard.GetState();
            gpPrevState = GamePad.GetState(PlayerIndex.One);
        }

        public static void addNewHighscore(int newScore) {
            int index = 9;
            while (newScore >= highscores[index])
            {
                if (index < 9)
                    highscores[index + 1] = highscores[index];
                index--;
                if (index < 0)
                    break;
            }
            if (index < 9)
            {
                highscores[index + 1] = newScore;
                newHighscore = index + 1;
                menuItems.Insert(index + 2, newScore.ToString());
                menuItems.RemoveAt(11);
            }
            SceneHighscores temp = new SceneHighscores(false);
            temp.SaveSomething();
        }

        public void SaveSomething()
        {
            lock (this)
            {
                if (!this.Saving)
                {
                    this.Saving = true;
                    //
                    // Create something to save
                    //GameState MyState = new GameState(100000, 20);
                    StorageDevice.BeginShowSelector(PlayerIndex.One, FinalizeSave, SceneHighscores.highscores);
                }
            }
        }

        /// <summary>
        /// Complete the serialization on a separate thread from the main update/rendering thread
        /// </summary>
        /// <param name="ar"></param>
        private void FinalizeSave(IAsyncResult ar)
        {
            //
            // Grab the object we want to save
            int[] MyState = (int[])ar.AsyncState;
            //
            // Only save something, if the operation was completed, i.e., the user might cancel the selection
            if (ar.IsCompleted)
            {
                StorageDevice MyDevice = StorageDevice.EndShowSelector(ar);
                IAsyncResult r = MyDevice.BeginOpenContainer("My Directory", null, null);
                r.AsyncWaitHandle.WaitOne();
                using (StorageContainer MyContainer = MyDevice.EndOpenContainer(r))
                {
                    using (Stream MyStream = MyContainer.CreateFile("HighScores.xml"))
                    {

                        XmlSerializer MySerializer = new XmlSerializer(typeof(int[]));
                        MySerializer.Serialize(MyStream, MyState);
                    }
                }
            }

            this.Saving = false;
        }

        /// <summary>
        /// Demonstrates how to deserialize an object from a storage device, on either a PC
        /// or the 360.
        /// </summary>
        private void LoadSomething()
        {
            lock (this)
            {
                if (!this.Loading)
                {
                    this.Loading = true;
                    StorageDevice.BeginShowSelector(PlayerIndex.One, FinalizeLoad, null);
                }
            }
        }

        /// <summary>
        /// Complete the serialization on a separate thread from the main update/rendering thread
        /// </summary>
        /// <param name="ar"></param>
        private void FinalizeLoad(IAsyncResult ar)
        {
            if (ar.IsCompleted)
            {
                StorageDevice MyDevice = StorageDevice.EndShowSelector(ar);
                IAsyncResult r = MyDevice.BeginOpenContainer("My Directory", null, null);
                r.AsyncWaitHandle.WaitOne();
                using (StorageContainer MyContainer = MyDevice.EndOpenContainer(r))
                {
                    using (Stream MyStream = MyContainer.OpenFile("HighScores.xml", FileMode.Open))
                    {
                        XmlSerializer MySerializer = new XmlSerializer(typeof(int[]));
                        SceneHighscores.highscores = (int[])MySerializer.Deserialize(MyStream);
                        SceneHighscores.menuItems.Clear();
                        menuItems.Add("HIGH SCORES");
                        for (int ct = 0; ct < 10; ct++)
                        {
                            menuItems.Add(highscores[ct].ToString());
                        }
                        HSLoaded = true;
                    }
                }
            }

            this.Loading = false;
        }


    }
}
